package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.stereotype.Autowired;
import com.lagou.edu.stereotype.Repository;
import com.lagou.edu.stereotype.Service;
import com.lagou.edu.scan.ClasspathPackageScanner;
import com.lagou.edu.stereotype.Transactional;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TODO
 *
 * @author chenx
 * @date 2021/4/24
 */
public class MyBeanFactory {
    private static Map<String,Object> map = new HashMap<>();  // 存储对象
    static {
        //1.扫描指定路径下的所有的类
        ClasspathPackageScanner classpathPackageScanner = new ClasspathPackageScanner("com.lagou.edu");
        try {
            //所有类的全限定类名
            List<String> classNameList = classpathPackageScanner.getFullyQualifiedClassNameList();
            for (String className:classNameList){
                Class<?> clazz = Class.forName(className);

                Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
                if (declaredAnnotations!=null){
                    for (int i = 0; i < declaredAnnotations.length; i++) {
                        String id;
                        switch (declaredAnnotations[i].annotationType().toString()){

                            case "com.lagou.edu.stereotype.Service":
                                Service service = clazz.getAnnotation(Service.class);
                                Object o= clazz.newInstance();;
                                id = StringUtils.isEmpty(service.value())?className.substring(className.lastIndexOf(".")+1):service.value();
                                map.put(id,o);
                                break;
//                            case "com.lagou.edu.stereotype.Repository":
//                                Repository repository = clazz.getAnnotation(Repository.class);
//                                id = StringUtils.isEmpty(repository.value())?className.substring(className.lastIndexOf(".")+1):repository.value();
//                                map.put(id,o);
//                                break;
//                            case "com.lagou.edu.stereotype.Autowired":
//                                Autowired autowired = clazz.getAnnotation(Autowired.class);
//                                id = StringUtils.isEmpty(autowired.value())?className.substring(className.lastIndexOf(".")+1):autowired.value();
//                                map.put(id,o);
//                                break;
                            case "com.lagou.edu.stereotype.Transactional":
                                Transactional transactional = clazz.getAnnotation(Transactional.class);
                                o= clazz.newInstance();;
                                id = StringUtils.isEmpty(transactional.value())?className.substring(className.lastIndexOf(".")+1):transactional.value();
                                map.put(id,o);
                                break;

                        }

                    }
                }
            }
            //维护bean之间的依赖关系
        for(Map.Entry<String,Object> entry:map.entrySet()){
            Object object = entry.getValue();
            Class<?> aClass = object.getClass();
            //获取属性
            Field[] fields = aClass.getFields();
            for(Field field:fields){
                //是否使用了@Autowired
                if(field.isAnnotationPresent(Autowired.class)){
                    //把该对象注入给该类
                    String name = field.getType().getName();//全限定名称
                    //具体的类
                    String id = name.substring(name.lastIndexOf(".")-1);
                    Method[] methods = aClass.getMethods();
                    for (int j = 0; j <methods.length ; j++) {
                        Method method = methods[j];
                        if(("set"+name).equalsIgnoreCase(method.getName())){
                            //bean之间的依赖关系（注入）
                            Object propertyObject = map.get(id);
                            method.invoke(id,propertyObject);
                        }
                    }
                    for (Method declaredMethod : aClass.getDeclaredMethods()) {
                        if (declaredMethod.getAnnotation(Transactional.class) != null) {
                            //获取代理工厂
                            //判断当前类是否有Transactional注解，若有则使用代理对象
                            ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                            Class[] face = aClass.getInterfaces();//获取类c实现的所有接口
                            //判断对象是否实现接口
                            if (face != null && face.length > 0) {
                                //实现使用JDK
                                object = proxyFactory.getJdkProxy(object);
                            } else {
                                //没实现使用CGLIB
                                object = proxyFactory.getCglibProxy(object);
                            }
                        }
                    }
                    // 把处理之后的object重新放到map中
                    map.put(entry.getKey(), object);

                }
            }


        }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id){
        return map.get(id);
    }
}
